﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Objects
{
    public interface IValidable
    {
        bool AutoValidate { get; set; }
        void AddValidationResult(ValidationResult res);
        bool Validate();
        bool Validate(bool Recurse);
        bool? IsValid { get; }
        ValidationResultList DescriptionValid { get; }
    }

    public class Validable<T> : Valuehost<T>, IValidable, IAbsorber<Validator>
    {
        protected override void Clone(ref Valuehost chain)
        {
            Validable<T> res;
            chain = res = (chain as Validable<T>) ?? new Validable<T>();
            base.Clone(ref chain);
            res.Validator = Validator;
        }

        public void AddValidationResult(ValidationResult res)
        {
            if (res != ValidationResult.Null)
                DescriptionValid.Inner.Add(res);
            foreach (var item in ((res as ValidationResultList) ?? ValidationResult.Null).GetAllResult())
                AddValidationResult(item);
        }

        private ValidationResultList _DescriptionValid;
        /// <summary>
        /// Результаты валидации. Можно установить значение null, после чего будет создана новая коллекция
        /// </summary>        
        public ValidationResultList DescriptionValid
        {
            get
            {
                if (_DescriptionValid == null)
                    _DescriptionValid = new ValidationResultList();
                return _DescriptionValid;
            }
            internal
            set
            {
                if (value == null)
                    _DescriptionValid = null;
                OnPropertyChanged("DescriptionValid");
            }
        }

        internal bool? _IsValid = null;
        /// <summary>
        /// Результат последней операции валидации
        /// </summary>        
        public bool? IsValid
        {
            get
            {
                if (AutoValidate)
                    Validate();
                return _IsValid;
            }
        }

        private bool _AutoValidate = false;
        /// <summary>
        /// 
        /// </summary>        
        public bool AutoValidate
        {
            get { return _AutoValidate; }
            set { _AutoValidate = value; }
        }

        /// <summary>
        /// Валидация
        /// </summary>
        /// <param name="Recurse">Рекурсивно</param>
        public virtual bool Validate(bool Recurse)
        {
            DescriptionValid.Inner.Clear();
            if (Validator != null)
                _IsValid = Validator.Validate(this, Recurse);
            else
                _IsValid = true;
            OnPropertyChanged("IsValid");
            OnPropertyChanged("DescriptionValid");
            return _IsValid.Value;
        }

        /// <summary>
        /// Валидация
        /// </summary>
        /// <param name="Recurse">Рекурсивно</param>
        public virtual bool Validate()
        {
            return Validate(true);
        }

        private Validator _Validator;
        /// <summary>
        /// Валидатор значения
        /// </summary>        
        public Validator Validator
        {
            get { return _Validator; }
            set { _Validator = value; }
        }

        public Validable() : base() { }
        public Validable(T Value) : base(Value) { }

        public override bool Inject(Valuehost value)
        {
            bool res = base.Inject(value);
            if (!res)
            {
                ValidInjector vli;
                if (res = ((vli = value as ValidInjector) != null))
                    Absorbe(vli.ValidValue);
            }
            return res;
        }

        #region IAbsorber<Validator> Members

        public object Absorbe(Validator val)
        {
            Validator += val;
            return this;
        }

        #endregion
    }
}
